pub mod sqsh;
pub mod error;
pub mod workspace;

pub use sqsh::*;
pub use error::*;
pub use workspace::*;

use crate::{byte::*, workspace::WorkSpace};

#[derive(Debug, Clone, Copy)]
pub enum SeqField {
    LiteralsLength,
    MatchLength,
    OffsetCodes,
}

#[derive(Debug, Clone, Copy)]
pub struct SeqTuple {
    pub literals_length:u32,
    pub match_length:u32,
    pub offset_value:u32,
}

#[derive(Debug)]
pub struct SeqSection {
    seq_section_header:SeqSectionHeader,
    seq_tuples:Vec<SeqTuple>,
}

impl SeqSection {
    pub fn serialize_into<W:ByteWrite>(&self,writer:&mut ByteWriter<W>) -> SeqResult<()> {
        self.seq_section_header.serialize_into(writer)?;
        todo!()
    }

    pub fn deserialize_from<R:ByteRead>(total_len:&mut u32,reader:&mut ByteReader<R>, workspace:&mut WorkSpace) -> SeqResult<Self> {
        let seq_section_header = SeqSectionHeader::deserialize_from(total_len, reader)?;
        workspace.load_seq_workspace(seq_section_header.symbol_compression_modes(), reader, total_len)?;
        let rest_data = Self::handle_rest_data(*total_len, reader)?;
        let mut seq_reader = ByteReader::new(std::io::Cursor::new(rest_data));
        let seq_tuples = Self::deserialize_seq_tuples_from(seq_section_header.num_of_seq(), &mut seq_reader, workspace)?;
        Ok(Self { seq_section_header, seq_tuples })
    }

    fn deserialize_seq_tuples_from<R:ByteRead>(num_of_seq:u32, reader:&mut ByteReader<R>, workspace:&WorkSpace) -> SeqResult<Vec<SeqTuple>> {
        let mut bit_reader = BitReader::new(reader);
        bit_reader.read_reverse_padding()?;

        let mut seq_tuples = Vec::new();
        let mut ll_cell = workspace.ll_workspace.first_cell(&mut bit_reader)?;
        let mut of_cell = workspace.of_workspace.first_cell(&mut bit_reader)?;
        let mut ml_cell = workspace.ml_workspace.first_cell(&mut bit_reader)?;
        for i in 0..num_of_seq {
            let ll_code = ll_cell.symbol;
            let ml_code = ml_cell.symbol;
            let of_code = of_cell.symbol;

            let (ll_base, ll_bits_num) = lookup_ll_code(ll_code);
            let (ml_base, ml_bits_num) = lookup_ml_code(ml_code);

            let of_add = bit_reader.read_reverse_bits::<u32>(of_code as usize)?;
            let ml_add = bit_reader.read_reverse_bits::<u32>(ml_bits_num as usize)?;
            let ll_add = bit_reader.read_reverse_bits::<u32>(ll_bits_num as usize)?;

            let literals_length = ll_base + ll_add;
            let match_length = ml_base + ml_add;
            let offset_value = (1u32 << of_code) + of_add;

            seq_tuples.push(SeqTuple { literals_length, match_length, offset_value });

            if i == num_of_seq - 1 { break; }
            workspace.ll_workspace.next_code(&mut bit_reader, &mut ll_cell)?;
            workspace.ml_workspace.next_code(&mut bit_reader, &mut ml_cell)?;
            workspace.of_workspace.next_code(&mut bit_reader, &mut of_cell)?;
        }
        assert!(!bit_reader.bits_remaining());
        Ok(seq_tuples)
    }

    fn handle_rest_data<R:ByteRead>(rest_len:u32,reader:&mut ByteReader<R>) -> SeqResult<Vec<u8>> {
        let data_len = rest_len as usize;
        let mut data = vec![0;data_len];
        reader.read_to_bytes(&mut data)?;
        data.reverse();
        Ok(data)
    }

    pub fn seq_tuples(&self) -> &[SeqTuple] {
        &self.seq_tuples
    }
}